//
//  UIViewController+Honda.m
//  Honda
//
//  Created by Wang.Xinlei on 4/22/13.
//  Copyright (c) 2013 HeninHoo. All rights reserved.
//

#import "MainViewController.h"

#import "UIViewController+Honda.h"

@implementation UIViewController (Honda)

- (void)presentView:(UIView *)viewToPresent completion:(void (^)(void))completion {
    [self presentView:[self enqueueObject:viewToPresent completion:completion] object:viewToPresent];
}

- (void)presentViewController:(UIViewController *)viewControllerToPresent completion:(void (^)(void))completion {
    [self presentView:[self enqueueObject:viewControllerToPresent completion:completion] object:viewControllerToPresent];
}

- (void)showView:(UIView *)viewToShowed enableDismiss:(BOOL)enableDismiss completion:(void (^)(void))completion {
    [self showView:[self enqueueObject:viewToShowed completion:completion] object:viewToShowed enableDismiss:enableDismiss];
}

- (void)showViewController:(UIViewController *)viewControllerToPresent enableDismiss:(BOOL)enableDismiss completion:(void (^)(void))completion {
    [self showView:[self enqueueObject:viewControllerToPresent completion:completion] object:viewControllerToPresent enableDismiss:enableDismiss];
}

- (void)popView:(UIView *)viewToPop from:(UIView *)from completion:(void (^)(void))completion {
    [self popView:[self enqueueObject:viewToPop completion:completion] from:from object:viewToPop];
}

- (void)popViewController:(UIViewController *)viewControllerToPop from:(UIView *)from completion:(void (^)(void))completion {
    [self popView:[self enqueueObject:viewControllerToPop completion:completion] from:from object:viewControllerToPop];
}

- (void)dismissWithCompletion:(void (^)(void))completion {
    id object = [self queuedObjects].lastObject;
    [self dismissView:[self deqeuqueLastObject:object completion:completion] object:object];
}

- (void)dismissFromParentViewControllerWithCompletion:(void (^)(void))completion {
    [self dismissView:[self deqeuqueLastObject:self completion:completion] object:self];
}

#pragma mark
- (void)onTapDismissShadow:(UIControl *)shadow {
    [self dismissWithCompletion:nil];
}

- (NSMutableArray *)disableDismissObjects {
    static NSMutableArray * s_disableDismissObjects = nil;
    @synchronized(s_disableDismissObjects) {
        if ([NSMutableArray invalid:s_disableDismissObjects]) {
            s_disableDismissObjects = [NSMutableArray new];
        }
        
        return s_disableDismissObjects;
    }
}

- (NSMutableArray *)queuedObjects {
    static NSMutableArray * s_queuedObjects = nil;
    @synchronized(s_queuedObjects) {
        if ([NSMutableArray invalid:s_queuedObjects]) {
            s_queuedObjects = [NSMutableArray new];
        }
        
        return s_queuedObjects;
    }
}

- (NSMutableDictionary *)centers {
    static NSMutableDictionary * s_centers = nil;
    @synchronized(s_centers) {
        if ([NSMutableDictionary invalid:s_centers]) {
            s_centers = [NSMutableDictionary new];
        }
        
        return s_centers;
    }
}

- (NSMutableDictionary *)presentOperatons {
    static NSMutableDictionary * s_presentOperatons = nil;
    @synchronized(s_presentOperatons) {
        if ([NSMutableDictionary invalid:s_presentOperatons]) {
            s_presentOperatons = [NSMutableDictionary new];
        }
        
        return s_presentOperatons;
    }
}

- (NSMutableDictionary *)dismissOperatons {
    static NSMutableDictionary * s_dismissOperatons = nil;
    @synchronized(s_dismissOperatons) {
        if ([NSMutableDictionary invalid:s_dismissOperatons]) {
            s_dismissOperatons = [NSMutableDictionary new];
        }
        
        return s_dismissOperatons;
    }
}

- (UIView *)staticBackgroundView {
    static UIView * s_staticBackgroundView = nil;
    @synchronized(s_staticBackgroundView) {
        if ([UIView invalid:s_staticBackgroundView]) {
            s_staticBackgroundView = [[UIView alloc] init];
        }
        
        return s_staticBackgroundView;
    }
}

- (UIView *)enqueueObject:(id)object completion:(void (^)(void))completion {
    if ([UIView invalid:object] && [UIViewController invalid:object]) {
        return nil;
    }
    
    [[self queuedObjects] addUniqueObject:object];
    
    if (nil != completion) {
        [[self presentOperatons] setObject:[NSBlockOperation blockOperationWithBlock:completion] forKey:@([object hash])];
    }
    
    UIView * view = object;
    if ([UIViewController valid:object]) {
        view = [object view];
    }
    
    return view;
}

- (UIView *)deqeuqueLastObject:(id)object completion:(void (^)(void))completion {
    if (nil != completion) {
        [[self dismissOperatons] setObject:[NSBlockOperation blockOperationWithBlock:completion] forKey:@([object hash])];
    }
    
    if ([UIView valid:object]) {
        return object;
    }
    
    if ([UIViewController valid:object]) {
        return [object view];
    }
    
    return nil;
}

- (UIControl *)showingControlWithView:(UIView *)view onClearBackgroundColor:(BOOL)clearBackgroundColor {
    UIView * staticBackgroundView = [self staticBackgroundView];
    
    if ([UIView invalid:staticBackgroundView.superview]) {
        UIView * parentView = [UIApplication sharedApplication].keyWindow.rootViewController.view;
        if ([UIView invalid:parentView]) {
            MainViewController *viewcon = [MainViewController sharedViewController];
            parentView = viewcon.view;
        }
        staticBackgroundView.backgroundColor = [UIColor clearColor];
        staticBackgroundView.frame = parentView.bounds;
        [parentView addSubview:staticBackgroundView];
    }

    UIControl * superShadowControl = (UIControl *)view.superview;
    if ([UIControl invalid:superShadowControl] || ! [staticBackgroundView isEqual:superShadowControl.superview]) {
        superShadowControl = [[[UIControl alloc] init] autorelease];
        superShadowControl.frame = staticBackgroundView.bounds;
        [superShadowControl addTarget:self action:@selector(onTapDismissShadow:) forControlEvents:UIControlEventTouchUpInside];
        [staticBackgroundView addSubview:superShadowControl];
        
        superShadowControl.backgroundColor = clearBackgroundColor ? [UIColor clearColor] : [UIColor colorWithWhite:0 alpha:0.25];

        [superShadowControl addSubview:view];
    }
    
    return superShadowControl;
}

- (UIControl *)hidingControlWithView:(UIView *)view {
    if ([UIControl valid:view.superview] && [[self staticBackgroundView] isEqual:view.superview.superview]) {
        return (UIControl *)view.superview;
    }
    
    return nil;
}

- (void)presentView:(UIView *)viewToPresent object:(id)object {
    if ([UIView invalid:viewToPresent]) {
        return;
    }
    
    [[UIApplication sharedApplication] beginIgnoringInteractionEvents];
    
    UIControl * showingControl = [self showingControlWithView:viewToPresent onClearBackgroundColor:NO];

    viewToPresent.center = CGPointMake(512, 768 + CGRectGetMidY(viewToPresent.bounds));
    [[self centers] setObject:[NSValue valueWithCGPoint:viewToPresent.center] forKey:@([object hash])];
    [UIView beginAnimations:@"presentView" context:(void *)object];
    [UIView setAnimationDelegate:self];
    [UIView setAnimationDidStopSelector:@selector(animationDidStop:finished:context:)];
    showingControl.alpha = 1;
    viewToPresent.center = CGPointMake(512, 384);
    [UIView commitAnimations];
}

- (void)showView:(UIView *)viewToShowed object:(id)object enableDismiss:(BOOL)enableDismiss {
    if ([UIView invalid:viewToShowed]) {
        return;
    }
    
    if ([[self disableDismissObjects] containsObject:object]) {
        [[self disableDismissObjects] removeObject:object];
        
        [[UIApplication sharedApplication] endIgnoringInteractionEvents];
    }
    [[UIApplication sharedApplication] beginIgnoringInteractionEvents];
    
    UIControl * showingControl = [self showingControlWithView:viewToShowed onClearBackgroundColor:NO];
    
    viewToShowed.center = CGPointMake(512, 384);
    [[self centers] setObject:[NSValue valueWithCGPoint:viewToShowed.center] forKey:@([object hash])];
    [UIView beginAnimations:@"showView" context:(void *)object];
    if (enableDismiss) {
        [UIView setAnimationDelegate:self];
        [UIView setAnimationDidStopSelector:@selector(animationDidStop:finished:context:)];
    }
    else {
        [[self disableDismissObjects] addObject:object];
    }
    showingControl.alpha = 1;
    [UIView commitAnimations];
}

- (void)popView:(UIView *)viewToPop from:(UIView *)from object:(id)object {
    if ([UIView invalid:viewToPop]) {
        return;
    }
    
    [[UIApplication sharedApplication] beginIgnoringInteractionEvents];
    
    UIControl * showingControl = [self showingControlWithView:viewToPop onClearBackgroundColor:YES];
    
    CGSize size = showingControl.bounds.size;
    CGRect frameOfFrom = [showingControl convertRect:from.bounds fromView:from];
    CGRect frameOfViewToPop = viewToPop.frame;
    if (size.height - CGRectGetMaxY(frameOfFrom) > CGRectGetHeight(frameOfViewToPop)) {
        frameOfViewToPop = CGRectMake(CGRectGetMinX(frameOfFrom), CGRectGetMaxY(frameOfFrom), CGRectGetWidth(frameOfFrom), CGRectGetHeight(frameOfViewToPop));
    }
    else if (CGRectGetMinY(frameOfFrom) > CGRectGetHeight(frameOfViewToPop)) {
        frameOfViewToPop = CGRectMake(CGRectGetMinX(frameOfFrom), CGRectGetMinY(frameOfFrom) - CGRectGetHeight(frameOfViewToPop), CGRectGetWidth(frameOfFrom), CGRectGetHeight(frameOfViewToPop));
    }
    else if (size.height / 2 > CGRectGetMidY(frameOfFrom)) {
        frameOfViewToPop = CGRectMake(CGRectGetMinX(frameOfFrom), CGRectGetMaxY(frameOfFrom), CGRectGetWidth(frameOfFrom), size.height - CGRectGetMaxY(frameOfFrom));
    }
    else {
        frameOfViewToPop = CGRectMake(CGRectGetMinX(frameOfFrom), 0, CGRectGetWidth(frameOfFrom), CGRectGetMinY(frameOfFrom));
    }
    viewToPop.frame = frameOfViewToPop;
    [[self centers] setObject:[NSValue valueWithCGPoint:viewToPop.center] forKey:@([object hash])];
    [UIView beginAnimations:@"popView" context:(void *)object];
    [UIView setAnimationDelegate:self];
    [UIView setAnimationDidStopSelector:@selector(animationDidStop:finished:context:)];
    showingControl.alpha = 1;
    [UIView commitAnimations];
}

- (void)dismissView:(UIView *)viewToDismiss object:(id)object {
    [[UIApplication sharedApplication] beginIgnoringInteractionEvents];
    
    UIControl * hidingControl = [self hidingControlWithView:viewToDismiss];
    
    NSValue * center = [[self centers] objectForKey:@([object hash])];
    [UIView beginAnimations:@"dismissView" context:(void *)object];
    [UIView setAnimationDelegate:self];
    [UIView setAnimationDidStopSelector:@selector(dismissAnimationDidStop:finished:context:)];
//    [UIView setAnimationDuration:4];
    hidingControl.alpha = 0;
    if ([NSValue valid:center]) {
        viewToDismiss.center = center.CGPointValue;
    }
    else {
        viewToDismiss.center = CGPointMake(512, 768 + CGRectGetMidY(viewToDismiss.bounds));
    }
    [UIView commitAnimations];
}

- (void)animationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context {
    [[UIApplication sharedApplication] endIgnoringInteractionEvents];
}

- (void)dismissAnimationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context {
    id object = context;
    if ([UIView valid:object]) {
        [[self hidingControlWithView:object] removeFromSuperview];
        [object removeFromSuperview];
    }
    
    if ([UIViewController valid:object]) {
        [[self hidingControlWithView:[object view]] removeFromSuperview];
        [[object view] removeFromSuperview];
    }
    
    // dismiss block
    NSBlockOperation * dismissBlock = [[self dismissOperatons] objectForKey:@([object hash])];
    if ([NSBlockOperation valid:dismissBlock]) {
        [[NSOperationQueue mainQueue] addOperation:dismissBlock];
        [[self dismissOperatons] removeObjectForKey:@([object hash])];
    }
    
    // present block
    NSBlockOperation * presentBlock = [[self presentOperatons] objectForKey:@([(id)context hash])];
    if ([NSBlockOperation valid:presentBlock]) {
        [[NSOperationQueue mainQueue] addOperation:presentBlock];
        [[self presentOperatons] removeObjectForKey:@([(id)context hash])];
    }
    
    [[self queuedObjects] removeObject:object];
    
    if ([[self disableDismissObjects] containsObject:object]) {
        [[self disableDismissObjects] removeObject:object];
        
        [[UIApplication sharedApplication] endIgnoringInteractionEvents];
    }
    [[UIApplication sharedApplication] endIgnoringInteractionEvents];

    if (0 == [self staticBackgroundView].subviews.count) {
        [[self staticBackgroundView] removeFromSuperview];
    }
}

@end


@implementation UIView (Honda)

- (void)dismissFromSupviewWithCompletion:(void (^)(void))completion {
    UIViewController * rootViewController = [UIApplication sharedApplication].keyWindow.rootViewController;
    [rootViewController dismissView:[rootViewController deqeuqueLastObject:self completion:completion] object:self];
}

@end
